#include "softmem.h"

LaneChannelShadowBufferFabricBusSender::LaneChannelShadowBufferFabricBusSender(JObject *parent) :
    LanePortSender(parent),
    dst_uri(new PortOut<int>(this)),
    r_data(new PortOut<std::complex<float>>(this)),
    sb_addr(new PortOut<int>(this)),
    ain_addr(new PortOut<int>(this))
{
}

void LaneChannelShadowBufferFabricBusSender::connect(LaneChannelShadowBufferFabricBusReceiver *sender)
{
    dst_uri->connect(sender->dst_uri);
    r_data->connect(sender->r_data);
    sb_addr->connect(sender->sb_addr);
    ain_addr->connect(sender->ain_addr);
}

void LaneChannelShadowBufferFabricBusSender::put(int data_dst_uri, std::complex<float> data_r_data, int data_sb_addr, int data_ain_addr)
{
    dst_uri->put(data_dst_uri);
    r_data->put(data_r_data);
    sb_addr->put(data_sb_addr);
    ain_addr->put(data_ain_addr);
}

void LaneChannelShadowBufferFabricBusSender::put_bypass(LaneChannelShadowBufferFabricBusReceiver *receiver)
{
    dst_uri->put(receiver->dst_uri->get());
    r_data->put(receiver->r_data->get());
    sb_addr->put(receiver->sb_addr->get());
    ain_addr->put(receiver->ain_addr->get());
}

bool LaneChannelShadowBufferFabricBusSender::is_any_full()
{
    return dst_uri->is_full() || r_data->is_full() || sb_addr->is_full() || ain_addr->is_full();
}

LaneChannelShadowBufferFabricBusReceiver::LaneChannelShadowBufferFabricBusReceiver(JObject *parent) :
    LanePortReceiver(parent),
    dst_uri(new PortIn<int>(this, -1)),
    r_data(new PortIn<std::complex<float>>(this, -1)),
    sb_addr(new PortIn<int>(this, -1)),
    ain_addr(new PortIn<int>(this, -1))
{
}

LaneChannelShadowBufferFabricBusPack LaneChannelShadowBufferFabricBusReceiver::get()
{
    LaneChannelShadowBufferFabricBusPack tmp_893891976;
    tmp_893891976.dst_uri = dst_uri->get();
    tmp_893891976.r_data = r_data->get();
    tmp_893891976.sb_addr = sb_addr->get();
    tmp_893891976.ain_addr = ain_addr->get();
    return tmp_893891976;
}

bool LaneChannelShadowBufferFabricBusReceiver::is_any_empty()
{
    return dst_uri->is_empty() || r_data->is_empty() || sb_addr->is_empty() || ain_addr->is_empty();
}

bool LaneChannelShadowBufferFabricBusReceiver::is_any_full()
{
    return dst_uri->is_full() || r_data->is_full() || sb_addr->is_full() || ain_addr->is_full();
}

ChannelShadowBufferFabricSender::ChannelShadowBufferFabricSender(JObject *parent) :
    ChannelPortSender(parent),
     Bus(new LaneChannelShadowBufferFabricBusSender(this))
{
}

ChannelShadowBufferFabricReceiver::ChannelShadowBufferFabricReceiver(JObject *parent) :
    ChannelPortReceiver(parent),
    Bus(new LaneChannelShadowBufferFabricBusReceiver(this))
{
}

void ChannelShadowBufferFabric::connect(ChannelShadowBufferFabricSender *sender, ChannelShadowBufferFabricReceiver *receiver)
{
    sender->Bus->connect(receiver->Bus);
}

NodeSoftmem::NodeSoftmem(Node *parent, NodeSoftmemParam params) :
    Node(parent)
{
    const_num_of_alu = params.num_of_alu;
    List<PackElement> tmp_893857744;
    for(int temp_884931944=0; temp_884931944<params.softmem_size; temp_884931944+=1)
    {
        tmp_893857744.append(PackElement());
    }
    reg_data = tmp_893857744;
    List<int> tmp_893857408;
    for(int temp_884931552=0; temp_884931552<params.num_of_alu; temp_884931552+=1)
    {
        tmp_893857408.append(0);
    }
    reg_alu_dst_pid = tmp_893857408;
    List<bool> tmp_893705016;
    for(int temp_884929760=0; temp_884929760<params.num_of_alu; temp_884929760+=1)
    {
        tmp_893705016.append(false);
    }
    reg_alu_sb = tmp_893705016;
    List<int> tmp_893705744;
    for(int temp_884932392=0; temp_884932392<params.num_of_alu; temp_884932392+=1)
    {
        tmp_893705744.append(0);
    }
    reg_alu_dst_uri = tmp_893705744;
    List<int> tmp_893706024;
    for(int temp_884997256=0; temp_884997256<params.num_of_alu; temp_884997256+=1)
    {
        tmp_893706024.append(0);
    }
    reg_alu_addr0 = tmp_893706024;
    List<bool> tmp_893681504;
    for(int temp_884995520=0; temp_884995520<params.num_of_alu; temp_884995520+=1)
    {
        tmp_893681504.append(false);
    }
    reg_alu_addr0_wait = tmp_893681504;
    List<bool> tmp_893681168;
    for(int temp_884996808=0; temp_884996808<params.num_of_alu; temp_884996808+=1)
    {
        tmp_893681168.append(false);
    }
    reg_alu_addr0_ain = tmp_893681168;
    List<int> tmp_893680608;
    for(int temp_884995968=0; temp_884995968<params.num_of_alu; temp_884995968+=1)
    {
        tmp_893680608.append(0);
    }
    reg_alu_addr1 = tmp_893680608;
    List<bool> tmp_893732568;
    for(int temp_884995408=0; temp_884995408<params.num_of_alu; temp_884995408+=1)
    {
        tmp_893732568.append(false);
    }
    reg_alu_addr1_wait = tmp_893732568;
    List<bool> tmp_893809216;
    for(int temp_884999112=0; temp_884999112<params.num_of_alu; temp_884999112+=1)
    {
        tmp_893809216.append(false);
    }
    reg_alu_addr1_ain = tmp_893809216;
    List<int> tmp_893811176;
    for(int temp_884999784=0; temp_884999784<params.num_of_alu; temp_884999784+=1)
    {
        tmp_893811176.append(0);
    }
    reg_alu_op_code = tmp_893811176;
    List<bool> tmp_893809552;
    for(int temp_885000456=0; temp_885000456<params.num_of_alu; temp_885000456+=1)
    {
        tmp_893809552.append(false);
    }
    reg_alu_has_work = tmp_893809552;
    List<bool> tmp_893811008;
    for(int temp_885001240=0; temp_885001240<params.num_of_alu; temp_885001240+=1)
    {
        tmp_893811008.append(false);
    }
    reg_alu_working = tmp_893811008;
    const_multiplexer = params.multiplexer;
    List<ChannelLoadFabricReceiver *> tmp_893811344;
    for(int temp_884953328=0; temp_884953328<params.num_of_main_memory; temp_884953328+=1)
    {
        tmp_893811344.append(new ChannelLoadFabricReceiver(this));
    }
    port_memory_receivers = tmp_893811344;
    List<ChannelStoreFabricSender *> tmp_893762360;
    for(int temp_884954168=0; temp_884954168<params.num_of_main_memory; temp_884954168+=1)
    {
        tmp_893762360.append(new ChannelStoreFabricSender(this));
    }
    port_memory_senders = tmp_893762360;
    port_mrunner_receiver = new ChannelLoadFabricReceiver(this);
    port_mrunner_sender = new ChannelLoadFabricSender(this);
    List<ChannelAluSender *> tmp_893761016;
    for(int temp_884955904=0; temp_884955904<params.num_of_alu; temp_884955904+=1)
    {
        tmp_893761016.append(new ChannelAluSender(this));
    }
    port_alu_senders = tmp_893761016;
    List<ChannelERunnerSoftmemReceiver *> tmp_893759560;
    for(int temp_884956744=0; temp_884956744<params.num_of_alu; temp_884956744+=1)
    {
        tmp_893759560.append(new ChannelERunnerSoftmemReceiver(this));
    }
    port_erunner_receivers = tmp_893759560;
    port_shadow_buffer = new ChannelShadowBufferFabricReceiver(this);
    port_sb_save = new ChannelShadowBufferFabricSender(this);
    ChannelShadowBufferFabric::connect(port_sb_save, port_shadow_buffer);
    List<PortOut<bool> *> tmp_894239632;
    for(int temp_885114752=0; temp_885114752<params.num_of_alu; temp_885114752+=1)
    {
        tmp_894239632.append(new PortOut<bool>(this));
    }
    port_halt_alu = tmp_894239632;
}

NodeTaskList NodeSoftmem::tasks() const
{
    NodeTaskList list;
    list.append(static_cast<NodeTask>(&NodeSoftmem::task_main_memory_load));
    list.append(static_cast<NodeTask>(&NodeSoftmem::task_shadow_buffer_load));
    list.append(static_cast<NodeTask>(&NodeSoftmem::task_mrunner_load));
    list.append(static_cast<NodeTask>(&NodeSoftmem::task_erunner_load));
    list.append(static_cast<NodeTask>(&NodeSoftmem::task_alu_load));
    list.append(static_cast<NodeTask>(&NodeSoftmem::task_deploy_request));
    return list;
}

void NodeSoftmem::task_main_memory_load()
{
    for(int temp_885115816=0; temp_885115816<const_multiplexer; temp_885115816+=1)
    {
        for(int temp_885116208=0; temp_885116208<port_memory_receivers.size(); temp_885116208+=1)
        {
            ChannelLoadFabricReceiver * memory_channel = port_memory_receivers[temp_885116208];
            if(memory_channel->Bus->is_any_empty())
            {
                continue;
            }
            reg_w_ain_addr = memory_channel->Bus->ain_addr->head();
            if(((reg_w_ain_addr)!=(-1))&&(!(reg_data[reg_w_ain_addr].ain)))
            {
                continue;
            }
            reg_w_sb_addr = memory_channel->Bus->sb_addr->head();
            if(((reg_w_sb_addr)!=(-1))&&(!(reg_data[reg_w_sb_addr].sb)))
            {
                continue;
            }
            LaneChannelLoadFabricBusPack ret_885046240 = memory_channel->Bus->get();
            reg_w_addr = ret_885046240.addr;
            reg_w_data = ret_885046240.data;
            reg_w_clr = ret_885046240.clr;
            if(reg_w_clr)
            {
                reg_data[reg_w_addr].sb = false;
                reg_data[reg_w_addr].msgin = false;
                reg_data[reg_w_addr].ain = false;
                reg_data[reg_w_addr].data = std::complex<float>(0.0, 0.0);
            }
            else
            {
                reg_data[reg_w_addr].sb = false;
                reg_data[reg_w_addr].msgin = true;
                reg_data[reg_w_addr].ain = false;
                reg_data[reg_w_addr].data = reg_w_data;
            }
        }
    }
}

void NodeSoftmem::task_shadow_buffer_load()
{
    if(port_shadow_buffer->Bus->is_any_empty())
    {
        return;
    }
    reg_sb_ain_addr = port_shadow_buffer->Bus->ain_addr->head();
    if(((reg_sb_ain_addr)!=(-1))&&(!(reg_data[reg_sb_ain_addr].ain)))
    {
        return;
    }
    reg_sb_sb_addr = port_shadow_buffer->Bus->sb_addr->head();
    if(((reg_sb_sb_addr)!=(-1))&&(!(reg_data[reg_sb_sb_addr].sb)))
    {
        return;
    }
    LaneChannelShadowBufferFabricBusPack ret_885101736 = port_shadow_buffer->Bus->get();
    reg_sb_w_addr = ret_885101736.dst_uri;
    reg_sb_w_data = ret_885101736.r_data;
    reg_data[reg_sb_w_addr].sb = false;
    reg_data[reg_sb_w_addr].msgin = true;
    reg_data[reg_sb_w_addr].ain = false;
    reg_data[reg_sb_w_addr].data = reg_sb_w_data;
}

void NodeSoftmem::task_mrunner_load()
{
    if(port_mrunner_receiver->Bus->is_any_empty())
    {
        return;
    }
    reg_m_ain_addr = port_mrunner_receiver->Bus->ain_addr->head();
    if(((reg_m_ain_addr)!=(-1))&&(!(reg_data[reg_m_ain_addr].ain)))
    {
        return;
    }
    reg_m_sb_addr = port_mrunner_receiver->Bus->sb_addr->head();
    if(((reg_m_sb_addr)!=(-1))&&(!(reg_data[reg_m_sb_addr].sb)))
    {
        if(!(port_shadow_buffer->Bus->is_any_full()))
        {
            LaneChannelLoadFabricBusPack ret_893555656 = port_mrunner_receiver->Bus->get();
            reg_m_addr = ret_893555656.addr;
            reg_m_data = ret_893555656.data;
            port_sb_save->Bus->put(reg_m_addr, reg_m_data, reg_m_sb_addr, reg_m_ain_addr);
        }
    }
    else
    {
        LaneChannelLoadFabricBusPack ret_893557952 = port_mrunner_receiver->Bus->get();
        reg_m_addr = ret_893557952.addr;
        reg_m_data = ret_893557952.data;
        reg_data[reg_m_addr].sb = false;
        reg_data[reg_m_addr].msgin = true;
        reg_data[reg_m_addr].ain = false;
        reg_data[reg_m_addr].data = reg_m_data;
    }
}

void NodeSoftmem::task_erunner_load()
{
    for(int ii=0; ii<const_num_of_alu; ii+=1)
    {
        if((!(reg_alu_has_work[ii]))&&(!(port_erunner_receivers[ii]->Read->is_any_empty())))
        {
            LaneChannelERunnerSoftmemReadPack ret_893661592 = port_erunner_receivers[ii]->Read->get();
            reg_alu_dst_pid[ii] = ret_893661592.dst_pid;
            reg_alu_sb[ii] = ret_893661592.sb;
            reg_alu_dst_uri[ii] = ret_893661592.dst_uri;
            reg_alu_addr0[ii] = ret_893661592.r_addr_0;
            reg_alu_addr0_wait[ii] = ret_893661592.r_addr_0_wait;
            reg_alu_addr0_ain[ii] = ret_893661592.r_ain_0_wait;
            reg_alu_addr1[ii] = ret_893661592.r_addr_1;
            reg_alu_addr1_wait[ii] = ret_893661592.r_addr_1_wait;
            reg_alu_addr1_ain[ii] = ret_893661592.r_ain_1_wait;
            reg_alu_op_code[ii] = ret_893661592.op_code;
            reg_alu_has_work[ii] = true;
        }
    }
}

void NodeSoftmem::task_alu_load()
{
    for(int ii=0; ii<const_num_of_alu; ii+=1)
    {
        if(port_alu_senders[ii]->Dst->is_any_empty())
        {
            continue;
        }
        LaneChannelAluDstPack ret_893564856 = port_alu_senders[ii]->Dst->get();
        reg_alu_dst_addr = ret_893564856.addr;
        reg_alu_dst_data = ret_893564856.data;
        reg_data[reg_alu_dst_addr].sb = false;
        reg_data[reg_alu_dst_addr].msgin = false;
        reg_data[reg_alu_dst_addr].ain = true;
        reg_data[reg_alu_dst_addr].data = reg_alu_dst_data;
        reg_alu_has_work[ii] = false;
        reg_alu_working[ii] = false;
    }
}

void NodeSoftmem::task_deploy_request()
{
    for(int ii=0; ii<const_num_of_alu; ii+=1)
    {
        if(!(reg_alu_has_work[ii]))
        {
            continue;
        }
        if((reg_alu_op_code[ii])==(100))
        {
            port_halt_alu[ii]->put(true);
            reg_alu_has_work[ii] = false;
            continue;
        }
        if((reg_alu_op_code[ii])<(20))
        {
            if((reg_alu_working[ii])||(port_alu_senders[ii]->Src->is_any_full()))
            {
                continue;
            }
            if((reg_alu_addr0_wait[ii])&&(!(reg_data[reg_alu_addr0[ii]].msgin)))
            {
                continue;
            }
            if((reg_alu_addr1_wait[ii])&&(!(reg_data[reg_alu_addr1[ii]].msgin)))
            {
                continue;
            }
            if((reg_alu_addr0_ain[ii])&&(!(reg_data[reg_alu_addr0[ii]].ain)))
            {
                continue;
            }
            if((reg_alu_addr1_ain[ii])&&(!(reg_data[reg_alu_addr1[ii]].ain)))
            {
                continue;
            }
            reg_data[reg_alu_addr0[ii]].msgin = false;
            reg_data[reg_alu_addr1[ii]].msgin = false;
            reg_alu_working[ii] = true;
            port_alu_senders[ii]->Src->put(reg_alu_dst_uri[ii], reg_data[reg_alu_addr0[ii]].data, reg_data[reg_alu_addr1[ii]].data, reg_alu_op_code[ii]);
            continue;
        }
        if((((20)==(reg_alu_op_code[ii]))||((20)<(reg_alu_op_code[ii])))&&((reg_alu_op_code[ii])<(100)))
        {
            if((reg_alu_op_code[ii])==(70))
            {
                if(reg_data[reg_alu_addr0[ii]].msgin)
                {
                    reg_alu_has_work[ii] = false;
                }
            }
            else
            {
                if((reg_alu_op_code[ii])==(20))
                {
                    if((reg_alu_dst_pid[ii])==(-1))
                    {
                        if((reg_alu_addr0_wait[ii])&&(!(reg_data[reg_alu_addr0_wait[ii]].msgin)))
                        {
                            continue;
                        }
                        for(int temp_893641840=0; temp_893641840<port_memory_senders.size(); temp_893641840+=1)
                        {
                            ChannelStoreFabricSender * memory_channel = port_memory_senders[temp_893641840];
                            if(memory_channel->Bus->is_any_full())
                            {
                                continue;
                            }
                            memory_channel->Bus->put(reg_data[reg_alu_addr0[ii]].data, reg_alu_dst_uri[ii]);
                            reg_data[reg_alu_addr0[ii]].sb = true;
                            reg_data[reg_alu_addr0[ii]].msgin = false;
                            reg_alu_has_work[ii] = false;
                        }
                    }
                    else
                    {
                        if(port_mrunner_sender->Bus->is_any_full())
                        {
                            continue;
                        }
                        port_mrunner_sender->Bus->put(reg_data[reg_alu_addr0[ii]].data, reg_alu_dst_uri[ii], reg_alu_dst_pid[ii], (reg_alu_sb[ii]) ? (reg_alu_dst_uri[ii]) : (-1), -1, false);
                        reg_data[reg_alu_addr0[ii]].sb = true;
                        reg_data[reg_alu_addr0[ii]].msgin = false;
                        reg_alu_has_work[ii] = false;
                    }
                }
            }
        }
    }
}